property ancestor,ilk
property pOuterFunction,pInnerFunction
property lTarget,lContext
property pBoundedVars
property _lingof_var_dep_

on new me,vardeps
  me.ilk = #LingoF_LambdaExpression
  if voidP(vardeps) then me._lingof_var_dep_ = []
  else me._lingof_var_dep_ = vardeps
  return me
end

-- APPLY
on GetAt me,x
  return me.LazyApply(x)
end

on SetAt me,x,y
end

on getUnboundedVars me
  if me._lingof_var_dep_ = [] then return [me]
  return me._lingof_var_dep_.duplicate()
end

on composeFunctions me,boundedVar
  if voidP(me.pInnerFunction) then return boundedVar.getPropAt(boundedVar.getPos(me))    
  return sApply(me.pOuterFunction,me.pInnerFunction.EvalWith(boundedVar),boundedVar)
end

on LazyApply me,x
  uv = (script "scrLambda").TryGetVarNames(x)
  repeat with v in me.getUnboundedVars()
    if not uv.getOne(v) then uv.add(v)
  end repeat
  
  lazyVar = (script "scrVarClosure").new(uv)
  lazyVar.lTarget = me
  lazyVar.lContext = x
  return lazyVar
end

on EvalWith me, boundedVar
  boundedVars = [:]
  if not voidP(me.pBoundedVars) then boundedVars = me.pBoundedVars.duplicate()
  repeat with i = 1 to boundedVar.count()
    boundedVars.AddProp(boundedVar.getPropAt(i) , boundedVar.getAt(i) )
  end repeat
  
  unboundedvars = []
  repeat with v in me.getUnboundedVars()
    if not boundedVars.getPos(v) then unboundedvars.add(v)
  end repeat
  
  if unboundedvars.count() then
    lazyVar = (script "scrVarClosure").new(unboundedvars)
    lazyVar.lTarget = me
    lazyVar.pBoundedVars = boundedVars
    return lazyVar
  end if
  
  if not voidP(me.pBoundedVars) then return me.lTarget.EvalWith(boundedVars)  
  if not voidP(me.lTarget) then return me.lTarget.ResumeApply(me.lContext,boundedVars)  
  return me.composeFunctions(boundedVars)
end

on ResumeApply me,nextObj,boundedVars
  if voidP(me.lTarget) then return sApply(me.composeFunctions(boundedVars),nextObj,boundedVars)
  else return sApply(me.lTarget.ResumeApply(me.lContext,boundedVars),nextObj,boundedVars)
end

on sApply x,y,b
  if listP(x) then 
    ii = Lingof().open().id
    ind = ii.ApplyOne(y,b)
    return x[ ind ]
    return x[y]
  end if
  return x.ApplyOne(y,b)
end